package com.timebank.websocket.service.impl;

import com.timebank.common.core.constant.StatusConstant;
import com.timebank.common.core.exception.ServiceException;
import com.timebank.common.core.utils.uuid.UUID;
import com.timebank.common.redis.utils.RedisUtil;
import com.timebank.websocket.consatnt.WSMessageConstant;
import com.timebank.websocket.consatnt.WebsocketConstant;
import com.timebank.websocket.mapper.WSMessageMapper;
import com.timebank.websocket.pojo.vo.OnlineUserVO;
import com.timebank.websocket.pojo.vo.SendMsgVO;
import com.timebank.websocket.service.WebsocketService;
import com.timebank.websocket.topic.WebsocketMsgPublisher;
import com.timebank.websocket.utils.WebsocketSpringContextUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * websocket 监听类(连接，断点，消息发送等)
 * <p>
 * /websocket/{userId}/{username}   =  /websocket/用户Id/用户名 来连接websocket，该参数会带到每一个监听方法中
 * </P>
 * @ServerEndpoint: socket链接地址
 *
 * @author shiliuyinzhen
 */
@Service
public class WebsocketServiceImpl implements WebsocketService {

    @Resource
    private WebsocketMsgPublisher msgPublisher;

    @Resource
    private WSMessageMapper wsMessageMapper;

    /**
     * 发送消息
     * @param sendMsgVO
     */
    @Override
    public void send(SendMsgVO sendMsgVO) {
        sendMsgVO.setId(UUID.randomUUID().toString());
        sendMsgVO.setOnlineNum(this.getOnlineCount());
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        sendMsgVO.setCreateTime(df.format(LocalDateTime.now()));
        sendMsgVO.setStatus(WSMessageConstant.MESSAGE_NOT_ACK);
        //取出接收者ids
        //将字符串转化为list数组和Long数组
        String getterIdsStr = sendMsgVO.getGetterId();
        List<Long> getterIdsList = Arrays.asList(getterIdsStr.split(",")).stream().map(s -> Long.parseLong(s.trim())).collect(Collectors.toList());
        Long[] getterIds = getterIdsList.toArray(new Long[getterIdsList.size()]);
        //持久化消息
        int row = wsMessageMapper.batchAddMessage(getterIds, sendMsgVO);
        if (row > 0){
            // 发送 redis 订阅消息
            msgPublisher.sendMsg(sendMsgVO);
        } else {
            throw new ServiceException("发送消息失败");
        }
    }

    /**
     * 获取当前在线列表
     * @return 用户map列表, ket = 用户id
     */
    @Override
    public Map<Object, OnlineUserVO> getOnlineUsers() {
        RedisUtil redisUtil = WebsocketSpringContextUtil.getBean(RedisUtil.class);
        Map<Object, Object> objectObjectMap = redisUtil.hEntries(WebsocketConstant.WEBSOCKET_CACHE_KEY);
        Map<Object, OnlineUserVO> map = new HashMap<>(4);
        for (Object key : objectObjectMap.keySet()) {
            OnlineUserVO vo = new OnlineUserVO();
            BeanUtils.copyProperties(objectObjectMap.get(key), vo);
            map.put(key, vo);
        }
        return map;
    }

    /**
     * 获取在线人数
     * @return int
     */
    @Override
    public Integer getOnlineCount() {
        RedisUtil redisUtil = WebsocketSpringContextUtil.getBean(RedisUtil.class);
        Long count = redisUtil.hSize(WebsocketConstant.WEBSOCKET_CACHE_KEY);
        return Integer.parseInt(count + "");
    }


    /**
     * 在线
     * 判断指定用户是否在线
     * @return true 在线 / false 不在线
     * @param userId 用户id
     */
    @Override
    public boolean isOnline(String userId) {
        RedisUtil redisUtil = WebsocketSpringContextUtil.getBean(RedisUtil.class);
        return redisUtil.hHasKey(WebsocketConstant.WEBSOCKET_CACHE_KEY, userId);
    }
}